﻿#include <QEventLoop>
#include <QMainWindow>
#include <QFileDialog>
#include <QTimer>
#include <QMessageBox>
#include <QProcess>
#include <QTextStream>
#include <QFileInfo>
#include <QDateTime>
#include <QDomDocument>
#include <QDomElement>

#include "routeimport.h"
#include "ui_routeimport.h"
#include "customwindow.h"

using namespace Custom;

RouteImport::RouteImport() :
    QWidget(),
    ui(new Ui::RouteImport)
{
    ui->setupUi(this);
    initControls();
    initConnection();
}

RouteImport::~RouteImport()
{
    delete ui;
}

Route RouteImport::showPopup()
{
    QObject del;//用于自动删除窗口
    RouteImport *detail = new RouteImport();
    auto *win = newModalWindow(QStringLiteral("航线导入"), detail, &del, false);
    detail->init();
    win->show();

    QEventLoop loop;
    Route ret;
    connect(detail, &RouteImport::routeLoaded, detail, [&ret](const Route &r)
    {
        ret = r;
    });
    connect(detail, &RouteImport::finished, &loop, &QEventLoop::quit);
    loop.exec();

    return ret;
}

bool RouteImport::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == parent() && event->type() == QEvent::Close)
    {
        emit finished();
        return true;
    }

    return QWidget::eventFilter(watched, event);
}

void RouteImport::init()
{
    QWidget *win = static_cast<QWidget *>(parent());
    connect(this, &RouteImport::finished, win, &QWidget::close);
    win->installEventFilter(this);
}

void RouteImport::initControls()
{
    ui->cbbType->addItem(QStringLiteral("Route plan exchange format - RTZ"));
    ui->cbbType->addItem(QStringLiteral("Furuno WPT (*.wpt)"));
    ui->cbbType->addItem(QStringLiteral("NRroute"));
    ui->cbbType->addItem(QStringLiteral("Planning Station 4.x rx4 route"));
    ui->cbbType->addItem(QStringLiteral("ChartWorld eGlobe G2"));
    ui->cbbType->addItem(QStringLiteral("ECPINS 6.0 - NMEA 0183"));
    ui->cbbType->addItem(QStringLiteral("Kongsberg v4 - v7"));
    ui->cbbType->addItem(QStringLiteral("Furuno"));
    ui->cbbType->addItem(QStringLiteral("Planning Station 3.x rtx route"));
    ui->cbbType->addItem(QStringLiteral("SAM Platinum"));
    ui->cbbType->addItem(QStringLiteral("Sperry Visionmaster v4 & v5"));
    ui->cbbType->addItem(QStringLiteral("Tokyo Keiki EC8x00"));
    ui->cbbType->addItem(QStringLiteral("Transas Navi-Sailor"));
    ui->cbbType->addItem(QStringLiteral("JRC"));
    ui->cbbType->addItem(QStringLiteral("BVS"));
    ui->cbbType->addItem(QStringLiteral("OpenCPN"));
}

void RouteImport::initConnection()
{
    connect(ui->btnStart, &QPushButton::clicked, this, &RouteImport::import);
    connect(ui->btnBrowse, &QPushButton::clicked, this, &RouteImport::browse);
}

QList<QGeoCoordinate> RouteImport::convertNrFile(const QString &fileName)
{
    QList<QGeoCoordinate> wpts;
    QFile file(fileName);
    if (file.open(QFile::ReadOnly | QFile::Text))
    {
        QTextStream ts(&file);
        ts.readLine();
        while (ts.atEnd() == false)
        {
            QString line = ts.readLine();
            QList<QString> words = line.split("\t");
            if (words.size() != 3)
            {
                wpts.clear();
                break;
            }

            bool success = false;
            double lat = words[0].toDouble(&success);
            if (success == false || lat < -90 || lat > 90)
            {
                wpts.clear();
                break;
            }

            double lon = words[1].toDouble(&success);
            if (success == false || lon < -180 || lon > 180)
            {
                wpts.clear();
                break;
            }

            wpts << QGeoCoordinate(lat, lon);
        }

        file.close();
    }

    return wpts;
}

QList<QGeoCoordinate> RouteImport::convertRtzFile(const QString &fileName)
{
    QList<QGeoCoordinate> wpts;
    QFile file(fileName);
    if (file.open(QFile::ReadOnly))
    {
        QDomDocument doc;
        doc.setContent(&file);
        file.close();

        QDomElement root = doc.documentElement();
        QDomElement e = root.firstChildElement("waypoints").firstChildElement("waypoint");
        QMap<int, QGeoCoordinate> map;
        while (e.isNull() == false)
        {
            int id = e.attribute("id").toInt();
            QDomElement position = e.firstChildElement("position");
            QGeoCoordinate wp;
            double lon = position.attribute("lon").toDouble();
            double lat = position.attribute("lat").toDouble();
            map[id] = QGeoCoordinate(lat, lon);

            e = e.nextSiblingElement("waypoint");
        }

        wpts = map.values();
    }

    return wpts;
}

QList<QGeoCoordinate> RouteImport::convertWptFile(const QString &fileName)
{
    QList<QGeoCoordinate> wpts;
    QFile file(fileName);
    if (file.open(QFile::ReadOnly))
    {
        QDataStream ds(&file);
        while (ds.atEnd() == false)
        {
            ds.skipRawData(8);
            double lon;
            double lat;
            ds.readRawData((char *)(&(lat)), 8);
            ds.readRawData((char *)(&(lon)), 8);
            lon = -lon;
            wpts << QGeoCoordinate(lat, lon);

            ds.skipRawData(64);
        }

        file.close();
    }

    return wpts;
}

void RouteImport::import()
{
    if (ui->cbbType->currentIndex() < 0)
    {
        QMessageBox::warning(this, QStringLiteral("航线"), QStringLiteral("没有选择航线类型"));
        return;
    }
    else if (QFile::exists(ui->edtFile->text()) == false)
    {
        QMessageBox::warning(this, QStringLiteral("航线"), QStringLiteral("航线文件不存在。"));
        return;
    }

    if (ui->edtName->text().isEmpty())
    {
        QFileInfo fi(ui->edtFile->text());
        ui->edtName->setText(fi.completeBaseName());
    }

    setEnabled(false);

    do
    {
        QString file = ui->edtFile->text();
        Route route = Route();
        if (ui->cbbType->currentIndex() == 0)
        {
            route.wpts = convertRtzFile(file);
        }
        else if (ui->cbbType->currentIndex() == 1)
        {
            route.wpts = convertWptFile(file);
        }
        else
        {
            if (ui->cbbType->currentIndex() != 2)
            {
                QString tempFile = qApp->applicationDirPath() + "\\temp.nrroute";
                if (QFile::exists(tempFile))
                {
                    QFile::remove(tempFile);
                }
                QProcess p;
                p.start(qApp->applicationDirPath() + "\\rtconv.exe",
                        QStringList() << file << tempFile << ui->cbbType->currentText());
                if(p.waitForFinished(10 * 1000))
                {
                    file = tempFile;
                }
                else
                {
                    p.terminate();
                    QMessageBox::warning(this, QStringLiteral("航线"), QStringLiteral("转换航线超时。"));
                    break;
                }
            }

            route.wpts = convertNrFile(file);
        }

        if (route.wpts.isEmpty())
        {
            QMessageBox::warning(this, QStringLiteral("航线"), QStringLiteral("获取航线失败。"));
            break;
        }

        route.name = ui->edtName->text();
        route.visible = true;
        route.createdTimestamp = QDateTime::currentMSecsSinceEpoch();
        emit routeLoaded(route);
        emit finished();
    } while (false);

    setEnabled(true);
}

void RouteImport::browse()
{
    QString fileName =  QFileDialog::getOpenFileName(this,
                                                     QStringLiteral("选择航线文件"));
    if (fileName.isEmpty())
    {
        return;
    }

    ui->edtFile->setText(fileName);
}
